#ifndef __MATCH_H__
#define __MATCH_H__
#include"room.hpp"
#include<list>
#include<condition_variable>
#include<thread>
template<typename T>
class match_queue
{
public:
    /*获取元素个数*/
    int size(){
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.size();
    }
    /*判断是否为空*/
    bool empty(){
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.empty();
    }
    /*阻塞线程----不放在pop里而是分离式防止，有两个数据的时候，要出队进入 房间的时候，出了一个他就阻塞了*/
    void wait(){
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }
    /*入队数据，并唤醒线程*/
    void push(const T& data){
        std::unique_lock<std::mutex> lock(_mutex);
        _list.push_back(data);
        _cond.notify_all();
    }
    /*出队数据*/
    bool pop(T& data){
        std::unique_lock<std::mutex> lock(_mutex);
        if(_list.empty()) return false;
        data=_list.front();
        _list.pop_front();
        return true;
    }
    /*移除指定数据*/
    void remove(T& data){
        std::unique_lock<std::mutex> lock(_mutex);
        _list.remove(data);//erase要用迭代器
    }


private:
    std::list<T> _list;
    std::mutex _mutex;
    std::condition_variable _cond;
};

class matcher
{
private:
    void handle_match(match_queue<uint64_t>& mq){
        while(1)
        {
            //1.判断队列人数是否大于2，<2则阻塞等待
            while(mq.size()<2)  
                mq.wait();
            //2.走到这说明人数已经够了，出队两个玩家
            uint64_t uid1,uid2;
            bool ret= mq.pop(uid1);
            if(ret==false)  continue;
            ret=mq.pop(uid2);
            if(ret==false){
                this->add(uid1);
                continue;
            }
            //3.校验两个玩家是否在线，如果有人掉线，就要把另一个人重新加入到对立(回到人不齐的情况) 
            wsserver_t::connection_ptr conn1=_om->get_conn_from_hall(uid1);
            if(conn1.get()==nullptr){
                this->add(uid2);
                continue;
            }
            wsserver_t::connection_ptr conn2=_om->get_conn_from_hall(uid2);
            if(conn2.get()==nullptr){
                this->add(uid1);
                continue;
            }
            //4.为两个玩家创建一个房间,并将玩家加入房间中，如果创建失败，就把他们全部放回匹配队列中等着
            room_ptr room=_rm->room_create(uid1,uid2);
            if(room.get()==nullptr){
                this->add(uid1);
                this->add(uid2);
                continue;
            }
            //5. 对两个玩家进行响应
            Json::Value resp;
            resp["optype"]="match_success";
            resp["result"]=true;
            std::string body;
            json_util::serialize(resp,body);
            conn1->send(body);
            conn2->send(body);
        }

    }
    void th_normal_entry(){return handle_match(_q_normal);}
    void th_high_entry(){return handle_match(_q_high);}
    void th_super_entry(){return handle_match(_q_super);}
public:
    matcher(online_manager* om,room_manager* rm,user_table* tb):_om(om),_rm(rm),_tb(tb),
    _th_normal(std::thread(&matcher::th_normal_entry,this)),
    _th_high(std::thread(&matcher::th_high_entry,this)),
    _th_super(std::thread(&matcher::th_super_entry,this)){      
        DLOG("游戏匹配对战初始化完成...");
    }
    /*根据玩家天梯分数，来判断玩家档次，添加到不同的匹配队列*/
    bool add(uint64_t uid){
        //1.根据用户ID，获取玩家信息
        Json::Value user;
        bool ret=_tb->select_by_id(uid,user);
        if(!ret){
            DLOG("没有玩家:%ld的信息",uid);
            return false;
        }
        //2.添加到指定的队列中
        int score=user["score"].asInt();
        if(score<2000){
            _q_normal.push(uid);
        }else if(score>=2000&&score<3000){
            _q_high.push(uid);
        }else{
            _q_super.push(uid);
        }
        return true;
    }
    void del(uint64_t uid){
        Json::Value user;
        bool ret=_tb->select_by_id(uid,user);
        if(!ret){
            DLOG("没有玩家:%ld的信息",uid);
            return;
        }
        int score=user["score"].asInt();
        if(score<2000){
            _q_normal.remove(uid);
        }else if(score>=2000&&score<3000){
            _q_high.remove(uid);
        }else{
            _q_super.remove(uid);
        }
    }

private:
    match_queue<uint64_t> _q_normal;
    match_queue<uint64_t> _q_high;
    match_queue<uint64_t> _q_super;
    std::thread _th_normal;
    std::thread _th_high;
    std::thread _th_super;
    online_manager* _om;
    room_manager* _rm;
    user_table* _tb;
};

#endif

